package com.digital.welcome.websocket;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.function.BiConsumer;

import javax.websocket.CloseReason;
import javax.websocket.CloseReason.CloseCode;

import org.springframework.stereotype.Component;

import com.digital.welcome.websocket.model.Message;
import com.digital.welcome.websocket.mywebsocket.IMyWebSocketPipeline;
import com.digital.welcome.websocket.mywebsocket.IWebSocketMessageService;
import com.digital.welcome.websocket.mywebsocket.IWebSocketSession;
import com.digital.welcome.websocket.mywebsocket.model.WebSocketMessage;
import com.digital.welcome.websocket.mywebsocket.model.WebSocketMessageEvent;
import com.digital.welcome.websocket.mywebsocket.model.WebSocketMessageType;

import cn.hutool.core.date.DateTime;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class OnMessageEndpoint implements IMyWebSocketPipeline {

    private HashMap<Long, Long> onlineUserId_webSocketIds = new HashMap<Long, Long>();

    private HashMap<Long, ArrayList<Message>> receiveId_messages = new HashMap<>();

    @Override
    public void myWebSocketExecutor(IWebSocketMessageService myWebSocket) {
        int[] intArray = new int[10];

        myWebSocket.addEventHandler(WebSocketMessageEvent.OnConnect, session_messages -> {
            ArrayList<WebSocketMessage> messages = session_messages[0].getValue();
            Long clientAssignedID = Long.parseLong((String)messages.get(0).getMessage());
            log.info("A Connect Request, Assigned ID : {}", clientAssignedID);
            ArrayList<WebSocketMessage> result = new ArrayList<WebSocketMessage>();
            result.add(new WebSocketMessage(
                WebSocketMessageEvent.OnServerConnect,
                WebSocketMessageType.Text,
                clientAssignedID.toString()
            ));
            return result;
        }).addEventHandler(WebSocketMessageEvent.OnDisconnect, session_messages -> {
            
            WebSocketMessage message = session_messages[0].getValue().get(0);
            IWebSocketSession session = session_messages[0].getKey();
            // Long clientWebSocketId = Long.parseLong((String)message.getMessage());
            Long clientWebSocketId = session.GetWebSocketId();
            log.info("Remove A Connection, ID : {}", clientWebSocketId);
            // remove online user
            long[] onlineUserId = new long[1];
            onlineUserId_webSocketIds.forEach(new BiConsumer<Long, Long>() {
                @Override
                public void accept(Long pOnlineUserId, Long pWebSocketId) {
                    if(pWebSocketId == clientWebSocketId) {
                        onlineUserId[0] = pOnlineUserId;
                    }
                }
            });
            onlineUserId_webSocketIds.remove(onlineUserId[0]);
            return new ArrayList();
        }).addEventHandler(WebSocketMessageEvent.OnClientConnect, session_messages -> {
            List<WebSocketMessage> messages = session_messages[0].getValue();
            IWebSocketSession session = session_messages[0].getKey();
            // 检查在线用户表中是否存在该用户,若存在把旧连接换成新连接,若不存在添加一个项
            Long clientAssignedId = Long.parseLong((String)messages.get(0).getMessage());
            Long userId = Long.parseLong((String)messages.get(1).getMessage());
            int eventId = messages.get(0).getMessageEvent().Code;
            log.info("Bind User {{ID = {}}} To WebSocketID {}", userId, clientAssignedId);

            if(onlineUserId_webSocketIds.get(userId) != null) {
                
                session.ClientClose(onlineUserId_webSocketIds.get(userId), new CloseReason(new CloseCode() {

                    @Override
                    public int getCode() {
                        return 200;
                    }
                    
                }, "Normal Closure"));
            }   
            onlineUserId_webSocketIds.put(userId, clientAssignedId);
            
            // Select Temp Messages Of A User
            ArrayList<Message> selectedMessages = receiveId_messages.get(userId);
            if(selectedMessages != null) {
                log.info("Selected {} Temporary Messages Of User {}", selectedMessages.size(), userId.toString());
            }
            receiveId_messages.put(userId, new ArrayList<>());
            selectedMessages = receiveId_messages.get(userId);
            // return selectedMessages;
            ArrayList<WebSocketMessage> result = new ArrayList<>();
            // result.add(new WebSocketMessage(
            //     WebSocketMessageEvent.OnServerTempMessage,
            //     WebSocketMessageType.Text,
            //     userId.toString()
            // ));
            result.addAll(Message.ToWebSocketMessageList(selectedMessages, WebSocketMessageEvent.OnServerTempMessage));
            
            return result;
            
        }).addEventHandler(WebSocketMessageEvent.OnClientMessage, session_messages -> {
            ArrayList<WebSocketMessage> messages = session_messages[0].getValue();
            IWebSocketSession session = session_messages[0].getKey();

            Message message = Message.ToMessages(messages, Message.TO_MESSAGES_PROP_OFFSET, Message.TO_MESSAGES_PROP_LENGTH).get(0);
            log.info("Receive A Message {} From User (ID = {}) To User(ID = {})", message.contentType, message.sendUserId, message.receiveUserId);
            // Select Server ID By User ID
            Long serverId = onlineUserId_webSocketIds.get(message.receiveUserId);

            // 统一改成服务器时间
            message.time = DateTime.now();
            if(serverId != null) { //说明待接收消息的用户在线
                ArrayList<Message> sendMessage = new ArrayList<>();
                sendMessage.add(message);
                ArrayList<WebSocketMessage> sendWSMessages = Message.ToWebSocketMessageList(sendMessage, WebSocketMessageEvent.OnServerMessage);
                session.SendMessage(serverId, sendWSMessages);

            }else {
                // Append Temporary Message
                if(receiveId_messages.get(message.receiveUserId) == null) {
                    receiveId_messages.put(message.receiveUserId, new ArrayList<>());
                }
                receiveId_messages.get(message.receiveUserId).add(message);
                log.info("Append A Temporary Message, Which Type : {}", message.contentType);
            }

            return new ArrayList<>();
        });
        
    }
    
}
